A duplicate Security Group rule was found
Error: WARN A duplicate Security Group rule was found on (sg-<censored>). This may be a side effect of a now-fixed Terraform issue causing two security groups with
identical attributes but different source_security_group_ids to overwrite each
information and instructions for recovery. Error: InvalidPermission.Duplicate: the specified rule "peer: sg-<censored>, TCP, from port: 80, to port: 80, ALLOW" already exists
識別子を作る (ハッシュ化) 際にルールの接続元にセキュリティグループを指定している場合 (source_security_group) で、かつ接続元と所属セキュリティグループの組み合わせが同じになる場合にハッシュが衝突するというもの。 こういうこと:
SG Aのルール: allow from SG B
SG Bのルール: allow from SG A
このP-Rは上記の問題を解決していて今は起こらないはずだが、なぜ2021年に起きたのか。
結論: aws_security_groupとaws_security_group_ruleを一時的にでも併用したことが原因
詳しく言うとにある以下の記述に抵触したことが原因: Terraform currently provides both a standalone Security Group Rule resource (a single ingress or egress rule), and a Security Group resource with ingress and egress rules defined in-line. At this time you cannot use a Security Group with in-line rules in conjunction with any Security Group Rule resources. Doing so will cause a conflict of rule settings and will overwrite rules.
aws_security_group と aws_security_group_rule を併用すると衝突するよ、と書いてある。
これは上記のハッシュ化ルールと組み合わせると起きそうなことである。
再現したコード・変更は以下の通り:
before (aws_security_groupのingressを指定している):
code:before.tf
resource "aws_security_group" "sg-a" {
vpc_id = "..."
ingress {
from_port = 80
to_port = 80
protocol = "-1"
}
}
after (ingressを消し、新たにaws_security_group_ruleリソースを追加):
code:after.tf
resource "aws_security_group" "sg-a" {
vpc_id = "..."
}
resource "aws_security_group_rule" "sg-a-ingress" {
type = "ingress"
security_group_id = aws_security_group.sg-a.id
from_port = 0
to_port = 0
protocol = "-1"
source_security_group = "<another security group id>"
}
code:diff.diff
diff --git a/./terraform/aws/staging/before.tf b/./terraform/aws/staging/after.tf
index c5af220..95c3339 100644
--- a/./terraform/aws/staging/before.tf
+++ b/./terraform/aws/staging/after.tf
@@ -1,9 +1,12 @@
resource "aws_security_group" "sg-a" {
vpc_id = "..."
- ingress {
- from_port = 80
- to_port = 80
- protocol = "-1"
- }
+}
+
+resource "aws_security_group_rule" "sg-a-ingress" {
+ type = "ingress"
+ security_group_id = aws_security_group.sg-a.id
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ source_security_group = "<another security group id>"
}
対処方法:
aws_security_group から ingress / egress をまず消す
aws_security_group_rule を追加する
という変更のapplyをそれぞれ分ける。
ingress/egressを消すと暗黙の全許可ルールが有効になるため、それが許容できない場合は:
新しい aws_security_group (ingress/egressなし)とaws_security_group_ruleを追加
……という手順になると思う。